package cn.coder.easyjson.stream;

import java.util.HashMap;
import java.util.Map;

import cn.coder.easyjson.JSON;
import cn.coder.easyjson.JSONArray;
import cn.coder.easyjson.JSONObject;
import cn.coder.easyjson.util.ObjectUtils;

public class JSONReader {
	private static final String PREFIX_ARRAY = "A";
	private static final String PREFIX_OBJECT = "J";
	private Map<String, String> cache;
	private static final int DEFAULT_CAPACITY = 64;

	public JSONReader() {
		this.cache = new HashMap<>(DEFAULT_CAPACITY);
	}

	public Object read(String json) {
		int type = check(json);

		if (type == 0)
			throw new RuntimeException("not a json string");

		json = json.trim();
		json = json.substring(1).substring(0, json.length() - 2);
		if (json.trim().length() == 0) {
			if (type == 1) {
				return new JSONObject();
			}
			if (type == 2) {
				return new JSONArray();
			}
		}

		StringBuffer temp = new StringBuffer(json);
		replaceBlock(temp, type, "[", "]");
		replaceBlock(temp, type, "{", "}");
		json = temp.toString();

		if (type == 1) {
			return ayncObject(json);
		}
		if (type == 2) {
			return ayncArray(json);
		}
		throw new RuntimeException("not a json string");
	}

	private static int check(String json) {
		if (JSON.validObject(json))
			return 1;
		if (JSON.validArray(json))
			return 2;
		return 0;
	}

	private void replaceBlock(final StringBuffer temp, int type, String c1, String c2) {
		int left = temp.lastIndexOf(c1);
		if (left > -1) {
			int right = temp.indexOf(c2, left);
			if (right > -1) {
				String uniqueKey = (type == 1 ? PREFIX_OBJECT : PREFIX_ARRAY) + System.nanoTime();
				this.cache.put(uniqueKey, temp.substring(left, right + 1));
				temp.replace(left, right + 1, uniqueKey);
				replaceBlock(temp, type, c1, c2);
			}
		}
	}

	private JSONArray ayncArray(String temp) {
		final JSONArray newArray = new JSONArray(this);
		ObjectUtils.split(temp, ",", new doToken() {

			@Override
			public void exec(String token) {
				token = token.trim();
				if (token.startsWith("'") || token.startsWith("\"")) {
					token = token.substring(1);
				}

				if (token.endsWith("'") || token.endsWith("\"")) {
					token = token.substring(0, token.length() - 1);
				}

				// if (lastValue != null) {
				// lastValue.append(",").append(str);
				// str = lastValue.toString();
				// lastValue = null;
				// }

				// if (lastValue == null)
				newArray.add(token);
			}

		});
		return newArray;
	}

	private JSONObject ayncObject(String temp) {
		final JSONObject newMap = new JSONObject(this);
		ObjectUtils.split(temp, ",", new doToken() {

			String lastKey = null;
			StringBuffer lastValue = null; // 防止字符串内有逗号

			@Override
			public void exec(String token) {
				if (token.contains(":")) {
					String[] keyValue = token.split(":");
					lastKey = trimKey(keyValue[0]);
					lastValue = new StringBuffer(keyValue[1]);
					if (keyValue.length > 2) {
						for (int i = 2; i < keyValue.length; i++) {
							lastValue.append(":").append(keyValue[i]);
						}
					}
				} else {
					lastValue.append(",").append(token);
				}
				newMap.put(lastKey, trimValue(lastValue));
			}

		});
		return newMap;
	}

	private static Object trimValue(StringBuffer lastValue) {
		return trimKey(lastValue.toString());
	}

	private static String trimKey(String str) {
		str = str.trim();
		if (str.startsWith("'") || str.startsWith("\""))
			str = str.substring(1);
		if (str.endsWith("'") || str.endsWith("\""))
			str = str.substring(0, str.length() - 1);
		return str;
	}

	public Object lazy(Object temp) {
		if (this.cache.size() == 0)
			return temp;
		if (temp instanceof JSONObject || temp instanceof JSONArray)
			return temp;
		if (this.cache.containsKey(temp)) {
			// 取得缓存的字符串
			temp = this.cache.remove(temp);
			temp = this.read(temp.toString());
		}
		return temp;
	}
}
